package org.example.weboj.service.impl;

import org.example.weboj.dto.ProblemCreateRequest;
import org.example.weboj.dto.ProblemDTO;
import org.example.weboj.dto.ProblemUpdateRequest;
import org.example.weboj.dto.TestCaseDTO;
import org.example.weboj.entity.Problems;
import org.example.weboj.entity.TestCases;
import org.example.weboj.mapper.ProblemsMapper;
import org.example.weboj.service.IProblemsService;
import org.example.weboj.service.ITestCasesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wza
 * @since 2025-04-03
 */
@Service
public class ProblemsServiceImpl extends ServiceImpl<ProblemsMapper, Problems> implements IProblemsService {
    
    @Autowired
    private ITestCasesService testCasesService;

    @Override
    public ProblemDTO getProblemDTOById(Long id) {
        Problems problem = this.getById(id);
        if (problem == null) {
            return null;
        }
        return convertToDTO(problem);
    }

    @Override
    public List<ProblemDTO> getAllProblemDTOs() {
        List<Problems> problems = this.list();
        return problems.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ProblemDTO createProblem(ProblemCreateRequest request, Long authorId) {
        // 创建题目实体
        Problems problem = new Problems();
        problem.setTitle(request.getTitle());
        problem.setDescription(request.getDescription());
        problem.setDifficulty(request.getDifficulty());
        problem.setTimeLimit(request.getTimeLimit());
        problem.setMemoryLimit(request.getMemoryLimit());
        problem.setAuthorId(authorId);
        problem.setCreatedAt(LocalDateTime.now());
        
        // 保存题目
        this.save(problem);
        
        // 创建测试用例
        if (request.getTestCases() != null && !request.getTestCases().isEmpty()) {
            List<TestCases> testCases = new ArrayList<>();
            for (ProblemCreateRequest.TestCaseCreateRequest tcRequest : request.getTestCases()) {
                TestCases testCase = new TestCases();
                testCase.setProblemId(problem.getId());
                testCase.setInput(tcRequest.getInput());
                testCase.setExpectedOutput(tcRequest.getExpectedOutput());
                testCase.setIsSample(tcRequest.getIsSample() != null ? tcRequest.getIsSample() : false);
                testCases.add(testCase);
            }
            testCasesService.saveBatch(testCases);
        }
        
        return convertToDTO(problem);
    }

    @Override
    @Transactional
    public ProblemDTO updateProblem(ProblemUpdateRequest request) {
        // 检查题目是否存在
        Problems existingProblem = this.getById(request.getId());
        if (existingProblem == null) {
            return null;
        }
        
        // 更新题目信息
        existingProblem.setTitle(request.getTitle());
        existingProblem.setDescription(request.getDescription());
        existingProblem.setDifficulty(request.getDifficulty());
        existingProblem.setTimeLimit(request.getTimeLimit());
        existingProblem.setMemoryLimit(request.getMemoryLimit());
        
        // 保存更新
        this.updateById(existingProblem);
        
        // 如果提供了测试用例，则更新测试用例
        if (request.getTestCases() != null) {
            // 删除原有测试用例
            testCasesService.removeByProblemId(request.getId());
            
            // 创建新的测试用例
            if (!request.getTestCases().isEmpty()) {
                List<TestCases> testCases = new ArrayList<>();
                for (ProblemCreateRequest.TestCaseCreateRequest tcRequest : request.getTestCases()) {
                    TestCases testCase = new TestCases();
                    testCase.setProblemId(request.getId());
                    testCase.setInput(tcRequest.getInput());
                    testCase.setExpectedOutput(tcRequest.getExpectedOutput());
                    testCase.setIsSample(tcRequest.getIsSample() != null ? tcRequest.getIsSample() : false);
                    testCases.add(testCase);
                }
                testCasesService.saveBatch(testCases);
            }
        }
        
        return convertToDTO(existingProblem);
    }

    @Override
    @Transactional
    public boolean deleteProblem(Long id) {
        // 检查题目是否存在
        Problems problem = this.getById(id);
        if (problem == null) {
            return false;
        }
        
        // 删除相关测试用例
        testCasesService.removeByProblemId(id);
        
        // 删除题目
        return this.removeById(id);
    }

    @Override
    @Transactional
    public List<ProblemDTO> batchCreateProblems(List<ProblemCreateRequest> requests, Long authorId) {
        List<ProblemDTO> createdProblems = new ArrayList<>();
        
        for (ProblemCreateRequest request : requests) {
            try {
                ProblemDTO problemDTO = createProblem(request, authorId);
                createdProblems.add(problemDTO);
            } catch (Exception e) {
                // 记录错误但继续处理其他题目
                // 可以考虑添加日志记录
                throw new RuntimeException("批量创建题目时发生错误: " + e.getMessage(), e);
            }
        }
        
        return createdProblems;
    }

    // 实体转DTO的私有方法
    private ProblemDTO convertToDTO(Problems problem) {
        // 获取该问题的所有测试用例
        List<TestCases> testCases = testCasesService.getByProblemId(problem.getId());

        // 转换为TestCaseDTO列表
        List<TestCaseDTO> testCaseDTOs = testCases.stream()
                .map(tc -> new TestCaseDTO(tc.getInput(), tc.getExpectedOutput(), tc.getIsSample()))
                .collect(Collectors.toList());

        return new ProblemDTO(
                problem.getId(),
                problem.getTitle(),
                problem.getDescription(),
                problem.getDifficulty(),
                problem.getTimeLimit(),
                problem.getMemoryLimit(),
                testCaseDTOs
        );
    }
}
